﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Reflection;
using System.Net;
using System.IO;
using System.Threading;
using System.Diagnostics;
using NOS.Security;
using NOS.Configuration.Services;


namespace NOS.Core
{
    public class NOSCore
    {

        #region . Funções Publicas .

        public string Process(string AbsolutPath,NameValueCollection Arguments)
        {
            string Command = "";
            string Service = "";
            string NameSpace = "";
            string ClassName = "";
            string FunctionName = "";           

            Command = AbsolutPath;
            if (Command != "")
            {
                try
                {
                    Service = Command.Split('/').GetValue(1).ToString().Replace("/", "");
                    Command = Command.Split('/').GetValue(2).ToString().Replace("/", "");
                    NameSpace = Command.Replace("::", "!").Split('!').GetValue(0).ToString();
                    Command = Command.Replace("::", "!").Split('!').GetValue(1).ToString();
                    ClassName = Command.Split('.').GetValue(0).ToString();
                    FunctionName = Command.Split('.').GetValue(1).ToString();
                }
                catch 
                {
                    return string.Format(ERROR_RESPONSE, "002", "Invalid service / call");
                }
            }

            Trace.WriteLine("Call Service: " + Service + "\nNameSpace...: " + NameSpace +
                            "\nClasse......: " + ClassName + "\nFunção......: " + FunctionName);

            return CallAssembly(Service, NameSpace, ClassName, FunctionName, Arguments);
        }

        public static void LoadAssembliesCache()
        {           
            DataObjectCollection objCollection = DataObjectCollection.LoadFromFile(AppDomain.CurrentDomain.BaseDirectory+"services.xml");

            Hashtable HashTemp = SafetyHashTable.GetExclusive();

            HashTemp.Clear();

            foreach (DataObject Obj in objCollection )
            {
                HashTemp.Add(Obj.ServiceName,new DataHashTable(Obj.ServiceName, Obj.Assembly, null));
            }

            SafetyHashTable.ReleaseExclusive();
        }

        #endregion

        #region . Funções Privadas .

        private string CallAssembly(string Service, string NameSpace, string ClassName, string FunctionName, NameValueCollection Arguments)
        {
            Assembly AssembLoaded = null;
            Object Obj = null;
            MethodInfo Minfo = null;
            string Retorno = "";
            
            Hashtable HashTemp = SafetyHashTable.GetShared();
            DataHashTable DataTmp = (DataHashTable)HashTemp[Service];
            try
            {
                if (DataTmp != null)
                {
                    if (DataTmp.LoadedAssembly != null)
                    {
                        AssembLoaded = DataTmp.LoadedAssembly;
                    }
                    else
                    {
                        string AssemblyFile = AppDomain.CurrentDomain.BaseDirectory + DataTmp.AssemblyPath;
                        AssembLoaded = Assembly.LoadFrom(AssemblyFile);
                        DataTmp.LoadedAssembly = AssembLoaded;
                    }
                }
                else
                {
                    return string.Format(ERROR_RESPONSE, "001", "Service not exist or not registred");
                }
            }
            finally
            {
                SafetyHashTable.ReleaseShared();
            }
            
            Type Tipo = AssembLoaded.GetType(NameSpace + "." + ClassName, false);
            if (Tipo != null)
            {
                Obj = Activator.CreateInstance(Tipo);
                Minfo = Tipo.GetMethod(FunctionName);
               
                ParameterInfo[] Parameters = Minfo.GetParameters();
                object[] Param = new object[Parameters.Length];
                for (int i = 0; i < Parameters.Length; i++ )
                {
                    if (Arguments[Parameters[i].Name] == null)
                    {
                        return string.Format(ERROR_RESPONSE, "003", "Invalid parameter in function "+FunctionName);
                    }
                    else if (Parameters[i].ParameterType == typeof(Int16) ||
                             Parameters[i].ParameterType == typeof(Int32) ||
                             Parameters[i].ParameterType == typeof(Int64))
                    {
                        Param[i] = Int32.Parse(Arguments[Parameters[i].Name]);
                    }
                    else if (Parameters[i].ParameterType == typeof(Double))
                    {
                        Param[i] = Double.Parse(Arguments[Parameters[i].Name]);
                    }
                    else
                    {
                        Param[i] = Arguments[Parameters[i].Name].ToString();
                    }
                }

                Retorno = Minfo.Invoke(Obj,Param).ToString();
            }
            return Retorno;
        }

        #endregion

        #region . Contantes .
     
        private const string ERROR_RESPONSE = "<?xml version=\"1.0\" encoding=\"utf-8\"?><NOS><ERRORCODE>{0}</ERRORCODE><ERROR>{1}</ERROR></NOS>";

        #endregion

    }
}